home *** CD-ROM | disk | FTP | other *** search
/ Network Supervisor's Toolkit / Network Supervisor's Toolkit.iso / printers / net_prnt / net_prin.pas < prev   
Pascal/Delphi Source File  |  1996-07-10  |  12KB  |  451 lines

  1. Program Novell_Printing_Example;
  2.  
  3. USES   DOS, CRT,  Unit_Sup;
  4.  
  5. {      Author:  Rick Ryan
  6.   Info Source: Novell API Reference, Volume I
  7.  
  8.   Demonstration of printing on Novell Advanced Netware 2.1+ using named
  9.   Print Queues and Servers.
  10.  
  11.   This method is required if you are using third party local printer sharing
  12.   software like Brightwork's PS-Print Plus since it is not possible to
  13.   assign a Netware Spooled Printer Number to one of these Queues.
  14.  
  15.   With Netware 2.1 the concept of printing changed so that queues are used
  16.   in place of Spooled Printers.  Spooled printers are still available, but
  17.   must be physically cabled to the server.  There is also a maximum of 5
  18.   spooled printers, but virtually no limit to the number of print queues
  19.   available.
  20.  
  21.   Blaise Power Tools+ 5.0 is required to recompile. (Or you can write your own
  22.   routines to replace the ones used here:
  23.  
  24.     __HiWrdSup()   - Extracts the high word from a long integer
  25.     __LoWrdSup()   - Extracts the low word from a long integer
  26.  
  27. }
  28. CONST
  29.   Default_Srvr   = 'SERVER_NAME';
  30.  
  31. Type
  32.   Printer_Type   = Record
  33.                      ServerName  : String[48];
  34.                      ServerID    : Byte;
  35.                      Q_Name      : String[48];
  36.                      Q_ID        : LongInt;
  37.                      PortNumber  : Byte;
  38.                    end;
  39. Var
  40.   Printer_Rec    : Printer_Type;
  41.   Reg            : DOS.Registers;
  42.   LST            : Text;
  43.  
  44.  
  45. Procedure Pause;
  46.   var
  47.     CH  : Char;
  48.   begin
  49.     gotoxy(1,25); clreol;
  50.     write('Press Any Key To Continue ');
  51.     ch := readkey;
  52.     gotoxy(1,25); clreol;
  53.   end;
  54.  
  55. Procedure Reverse_Longint(var Long: Longint);
  56.   var
  57.     Long_Array  : array[1..4] of byte absolute Long;
  58.     Long_Temp   : array[1..4] of byte;
  59.     Loop        : Byte;
  60.   begin
  61.     For Loop := 1 to 4 do Long_Temp[Loop] := Long_Array[Loop];
  62.     Long_Array[4] := Long_Temp[1];
  63.     Long_Array[3] := Long_Temp[2];
  64.     Long_Array[2] := Long_Temp[3];
  65.     Long_Array[1] := Long_Temp[4];
  66.   end;
  67.  
  68.  
  69. Function Server_Exists(S: String; var SID: Byte): Boolean;
  70.  
  71.   { Checks that the named server exists on this network and obtains the
  72.     offset into the Server Name Table as the ID.  If the server exists,
  73.     this function returns TRUE
  74.   }
  75.  
  76.   type
  77.     Server_Lists  = Array[1..8,1..48] of char;
  78.   var
  79.     Server_List   : ^Server_Lists;
  80.     A_Name        : String;
  81.     Loop1,
  82.     Loop2         : Byte;
  83.   begin
  84.     For Loop1 := 1 to length(S) do S[Loop1] := upcase(S[Loop1]);
  85.     Reg.AH := $EF;
  86.     Reg.AL := $04;
  87.     intr($21,Reg);
  88.     Server_List := ptr(Reg.ES,Reg.SI);
  89.     Loop1 := 0;
  90.     repeat
  91.       inc(Loop1);
  92.       A_Name := '';
  93.       Loop2 := 1;
  94.       while Server_List^[Loop1,Loop2] <> #0 do
  95.         begin
  96.           A_Name := A_Name + Server_List^[Loop1,Loop2];
  97.           inc(Loop2);
  98.         end;
  99.     until ((A_Name = S) or (Loop1 = 8));
  100.     if A_Name = S then
  101.       begin
  102.         SID := Loop1;
  103.         Server_Exists := TRUE;
  104.       end
  105.     else
  106.       begin
  107.         SID := 0;
  108.         Server_Exists := FALSE;
  109.       end;
  110.   end;
  111.  
  112.  
  113. Function Q_Exists(Q: String; var Q_ID: Longint): Boolean;
  114.  
  115.   { Checks that the Print Queue Name exists on the network and obtains
  116.     the bindery object id for the queue.  If the queue exists and
  117.     no errors occurred, the function returns TRUE
  118.   }
  119.  
  120.   Var
  121.     ReqBuf   : Record
  122.                  BufLen   : Integer;
  123.                  SubFunc  : Byte;
  124.                  LastSeen : Longint;
  125.                  SrchType : Integer;
  126.                  NameLen  : Byte;
  127.                  ObjName  : Array[1..48] of char;
  128.                end;
  129.     RepBuf   : Record
  130.                  BufLen   : Integer;
  131.                  ObjId    : Longint;
  132.                  ObjType  : Integer;
  133.                  ObjName  : Array[1..48] of char;
  134.                  ObjFlag  : Byte;
  135.                  ObjSec   : Byte;
  136.                  ObjProps : Byte;
  137.                end;
  138.     Loop     : Integer;
  139.     BindType : Integer;
  140.     OK       : Boolean;
  141.     A_Queue  : String;
  142.  
  143.   begin
  144.     BindType := 3;  { Even though Novell says this is a Print Server type }
  145.  
  146.     for Loop := 1 to length(Q) do Q[Loop] := upcase(Q[Loop]);
  147.  
  148.     fillchar(ReqBuf,Sizeof(ReqBuf),#0);
  149.     fillchar(RepBuf,Sizeof(RepBuf),#0);
  150.  
  151.     Reg.AH := $E3;
  152.     Reg.DS := Seg(ReqBuf);
  153.     Reg.SI := Ofs(ReqBuf);
  154.     Reg.ES := Seg(RepBuf);
  155.     Reg.DI := Ofs(RepBuf);
  156.  
  157.     ReqBuf.BufLen := sizeof(ReqBuf) - 2;
  158.     ReqBuf.SubFunc := $37;
  159.  
  160.     ReqBuf.LastSeen := -1;
  161.     Reverse_LongInt(ReqBuf.LastSeen);
  162.  
  163.     ReqBuf.SrchType := BindType;
  164.     ReqBuf.SrchType := swap(ReqBuf.SrchType);
  165.  
  166.     ReqBuf.NameLen := length(Q);
  167.     for Loop := 1 to length(Q) do ReqBuf.ObjName[Loop] := Q[Loop];
  168.     RepBuf.BufLen := sizeof(RepBuf);
  169.  
  170.     repeat
  171.       A_Queue := '';
  172.       intr($21,Reg);
  173.       OK := (Reg.AL = $00);
  174.       if OK then
  175.         begin
  176.           Loop := 1;
  177.           while RepBuf.ObjName[Loop] <> #0 do
  178.             begin
  179.               A_Queue := A_Queue + RepBuf.ObjName[Loop];
  180.               inc(Loop);
  181.             end;
  182.           ReqBuf.LastSeen := RepBuf.ObjId;
  183.         end;
  184.     until ((A_Queue = Q) or (NOT OK));
  185.     if OK then
  186.       begin
  187.         Q_ID := RepBuf.ObjID;
  188.         Q_Exists := TRUE;
  189.       end
  190.     else
  191.       begin
  192.         Q_ID := 0;
  193.         Q_Exists := FALSE;
  194.       end;
  195.   end;
  196.  
  197. Procedure Get_Printer_Record;
  198.   { simulates what would be stored in a printer definition file }
  199.   var
  200.     OK   : Boolean;
  201.     Loop : Byte;
  202.   begin
  203.     clrscr;
  204.     with Printer_Rec do
  205.       begin
  206.  
  207.         {Get & Check Server Name}
  208.  
  209.         repeat
  210.           OK := TRUE;
  211.           gotoxy(1,3); clreol; write('Server Name (',Default_Srvr,'): ');
  212.           readln(ServerName);
  213.           for Loop := 1 to length(ServerName) do ServerName[Loop] := upcase(ServerName[Loop]);
  214.           if length(ServerName) = 0 then ServerName := Default_Srvr;
  215.           OK := Server_Exists(ServerName,ServerID);
  216.           if not OK then
  217.             begin
  218.               gotoxy(1,23); clreol;
  219.               write(#7,'That server does not exist on this network.');
  220.               Pause;
  221.               gotoxy(1,23); clreol;
  222.             end;
  223.         until OK;
  224.  
  225.         {Get & Check Queue Name}
  226.  
  227.         repeat
  228.           OK := TRUE;
  229.           gotoxy(1,5); clreol; write('       Print Queue Name: ');
  230.           readln(Q_Name);
  231.           For Loop := 1 to length(Q_Name) do Q_Name[Loop] := upcase(Q_Name[Loop]);
  232.           OK := Q_Exists(Q_Name,Q_ID);
  233.           if not OK then
  234.             begin
  235.               gotoxy(1,23); clreol;
  236.               write(#7,'That queue does not exist on this network.');
  237.               Pause;
  238.               gotoxy(1,23); clreol;
  239.             end;
  240.         until OK;
  241.  
  242.         { Which LPT port in this workstation should the shell reassign to
  243.           the print queue we just got?  If you have a local printer, don't
  244.           use LPT1 or the local printer goes away.  LPT3 is what I always
  245.           use.
  246.         }
  247.  
  248.         repeat
  249.           OK := TRUE;
  250.           gotoxy(1,7); clreol; write(' Local Printer Port No.: ');
  251.           readln(PortNumber);
  252.           OK := (PortNumber in [1,2,3]);
  253.           if not OK then
  254.             begin
  255.               gotoxy(1,23); clreol;
  256.               write(#7,'Printer Port Number Must Be 1, 2 or 3.');
  257.               Pause;
  258.               gotoxy(1,23); clreol;
  259.             end;
  260.           until OK;
  261.  
  262.         gotoxy(1,20); clreol; writeln('Printing To Queue ',Q_Name,' On Server ',ServerName,'.');
  263.       end;
  264.   end;
  265.  
  266. Function Set_Capture_Print_Q: Boolean;
  267.  
  268.   { Sets the print queue and server for the next capture of the local LPT
  269.     device.  If no errors were encountered, the function returns TRUE
  270.   }
  271.  
  272.   var
  273.     OK    : Boolean;
  274.   begin
  275.     Reg.AH := $B8;
  276.     Reg.AL := $06;
  277.     Reg.DH := Printer_Rec.PortNumber - 1;
  278.     Reg.DL := Printer_Rec.ServerID;
  279.     Reg.BX := __LoWrdSup(Printer_Rec.Q_ID);
  280.     Reg.CX := __HiWrdSup(Printer_Rec.Q_ID);
  281.     intr($21,Reg);
  282.     Set_Capture_Print_Q := (Reg.AL = $00);
  283.   end;
  284.  
  285. Function Set_Specific_Print_Job_Flags: Boolean;
  286.  
  287.   { This function turns off the Banner Page and the End of Job Form Feed
  288.     for the Specified LPT Port.  If there are no errors encountered, the
  289.     function returns TRUE
  290.   }
  291.  
  292.   var
  293.     ReqBuf  : Record
  294.                 Status        : Byte;
  295.                 Flags         : Byte;
  296.               end;
  297.   begin
  298.     Reg.AH := $B8;
  299.     Reg.AL := $03;
  300.     Reg.CX := 2;  {length of buffer}
  301.     Reg.ES := Seg(ReqBuf);
  302.     Reg.BX := Ofs(ReqBuf);
  303.     Reg.DH := Printer_Rec.PortNumber - 1;
  304.  
  305.     { Flag Values Are:
  306.  
  307.        $04 - Print Interrupted Capture
  308.        $08 - Suppress Form Feed at End Of Job
  309.        $40 - Enable Tab Expansion
  310.        $80 - Print A Banner Page
  311.     }
  312.  
  313.     ReqBuf.Flags := $08;
  314.     intr($21,Reg);
  315.     Set_Specific_Print_Job_Flags := (Reg.AL = $00);
  316.   end;
  317.  
  318. Function Start_Specific_Capture: Boolean;
  319.   begin
  320.     Reg.AH := $DF;
  321.     Reg.DL := $04;
  322.     Reg.DH := Printer_Rec.PortNumber - 1;
  323.     intr($21,Reg);
  324.     Start_Specific_Capture := (Reg.AL = $00);
  325.   end;
  326.  
  327. Function Open_LPT_Port: Boolean;
  328.   var
  329.     PortName : String;
  330.   begin
  331.     str(Printer_Rec.PortNumber,PortName);
  332.     PortName := 'LPT'+PortName;
  333.     {$I-}
  334.     assign(LST,PortName);
  335.     {$I+}
  336.     if IOResult = 0 then
  337.       begin
  338.         {$I-}
  339.         rewrite(LST);
  340.         {$I+}
  341.         if IOResult <> 0 then Open_LPT_Port := FALSE
  342.         else Open_LPT_Port := TRUE;
  343.       end
  344.     else
  345.       Open_LPT_Port := FALSE;
  346.   end;
  347.  
  348. Function Begin_Qing: Boolean;
  349.  
  350.   { This function sets up a network printer for receiving text sent to the
  351.     LST text variable.  If no errors are encountered the function returns
  352.     TRUE.
  353.   }
  354.  
  355.   var
  356.     OK   : Boolean;
  357.   begin
  358.     OK := FALSE;
  359.     if Set_Capture_Print_Q then
  360.       if Set_Specific_Print_Job_Flags then
  361.         if Start_Specific_Capture then
  362.           if Open_LPT_Port then
  363.             OK := TRUE;
  364.     Begin_Qing := OK;
  365.   end;
  366.  
  367. Function Close_LPT_Port: Boolean;
  368.  
  369.   { Closes the text variable LST and returns TRUE if no errors were
  370.     encountered
  371.   }
  372.  
  373.   begin
  374.     {$I-}
  375.     close(LST);
  376.     {$I+}
  377.     if IOResult = 0 then Close_LPT_Port := TRUE
  378.     else Close_LPT_Port := FALSE;
  379.   end;
  380.  
  381. Function End_Specific_Capture: Boolean;
  382.  
  383.   { Stops the capture for the named local port (which causes all text to
  384.     be placed in the named print queue for printing) and returns TRUE if
  385.     no errors were encountered.
  386.   }
  387.  
  388.   begin
  389.     Reg.AH := $DF;
  390.     Reg.DL := $05;
  391.     Reg.DH := Printer_Rec.PortNumber - 1;
  392.     intr($21,Reg);
  393.     End_Specific_Capture := (Reg.AL = $00);
  394.   end;
  395.  
  396. Function End_Qing: Boolean;
  397.  
  398.   { Closes LST text variable and stops capture on the named local printer
  399.     port.  Function returns TRUE if no errors were encountered.
  400.   }
  401.  
  402.   var
  403.     OK   : Boolean;
  404.   begin
  405.     OK := FALSE;
  406.     if Close_LPT_Port then
  407.       if End_Specific_Capture then
  408.         OK := TRUE;
  409.     End_Qing := OK;
  410.   end;
  411.  
  412. Procedure Print_Something;
  413.   var
  414.     A_Line  : String;
  415.     A_Num   : String;
  416.     Loop    : Byte;
  417.   begin
  418.     gotoxy(1,14);
  419.     clreol;
  420.     write('Printing ');
  421.     A_Line := 'Line xx : ABCDEFGHIJKLMNOPQRSTUVWYXYZ 0123456789 ';
  422.     for Loop := 1 to 50 do
  423.       begin
  424.         str(Loop:2,A_Num);
  425.         A_Line[6] := A_Num[1];
  426.         A_Line[7] := A_Num[2];
  427.         {$I-}
  428.         writeln(LST,A_Line);    { Most common error is RunTime #152 which }
  429.                                 { means the port really was not opened b/c }
  430.                                 { of some error setting up for the queue }
  431.         {$I+}
  432.         if IOResult <> 0 then
  433.           begin
  434.             writeln('Error');
  435.             exit;
  436.           end;
  437.         write('.');
  438.       end;
  439.   end;
  440.  
  441.  
  442. BEGIN
  443.   Get_Printer_Record;
  444.   if End_Specific_Capture then begin { Do Nothing } end;
  445.   if Begin_Qing then
  446.     begin
  447.       Print_Something;
  448.       if End_Qing then begin end;
  449.     end;
  450.   Pause;
  451. END.